 /*******************************************************************************
  * Copyright (c) 2004, 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.intro.impl.model;

 import java.util.List ;
 import java.util.Vector ;

 import org.eclipse.ui.internal.intro.impl.model.url.IntroURLParser;

 /*
  * Intro History Model.
  */
 public class History {
     // History of Intro Pages and real URL visited by Intro Browser. All
 // elements are all of type HistoryObject.
 private Vector history = new Vector ();
     private int navigationLocation = 0;


     // Model class for history objects. A history object may be a url or an
 // Intro page. A url is a regular URL navigated to from a fully qualified
 // link. An intro page may be an IFrame page. IFrame pages are not created
 // for every Help topic navigated in an embedded IFrame. Instead the same
 // IFrame is stored in history as a different object with the IFrameURL set.
 // This way the model actually creates one page for every embedded Help
 // Topic target but the navigation history updates the IFrame accordingly.
 class HistoryObject {
         AbstractIntroPage page;
         String iframeUrl;
         String url;

         HistoryObject(Object location) {
             if (location instanceof String )
                 this.url = (String ) location;

             if (location instanceof AbstractIntroPage) {
                 this.page = (AbstractIntroPage) location;
                 // will be set to null if the page is not an IFrame page.
 this.iframeUrl = this.page.getIFrameURL();
             }
         }

         /**
          * returns the history page. If iframe page, updated to correct url.
          *
          * @return
          */
         AbstractIntroPage getPage() {
             if (page.isIFramePage())
                 // when page was stored, the IFrame url was also stored. Make
 // sure to return the same state. The page is the same, only the
 // IFrame url changes.
 page.setIFrameURL(getIFrameUrl());
             return page;
         }

         String getPageId() {
             return page.getId();
         }

         String getIFrameUrl() {
             return iframeUrl;
         }

         String getUrl() {
             return url;
         }

         boolean isURL() {
             return (url != null) ? true : false;
         }

         boolean isIntroPage() {
             return (page != null) ? true : false;
         }

         boolean isIFramePage() {
             return (iframeUrl != null) ? true : false;
         }

     }


     /**
      * Updates the UI navigation history with either a real URL, or a page ID.
      *
      * @param pageId
      */
     public void updateHistory(String location) {
         // quick exit.
 if (!history.isEmpty() && isSameLocation(location))
             // resetting the same location is useless.
 return;
         doUpdateHistory(location);
     }

     /**
      * Updates the UI navigation history with either a real URL, or a page ID.
      *
      * @param page
      */
     public void updateHistory(AbstractIntroPage page) {
         // quick exit.
 if (!history.isEmpty() && isSameLocation(page))
             // resetting the same location is useless.
 return;
         doUpdateHistory(page);
     }

     private void doUpdateHistory(Object location) {
         // we got here due to an intro URL listener or an SWT Form hyperlink
 // listener. location may be a url or an IntroPage.
 if (navigationLocation == getHistoryEndPosition())
             // we are at the end of the vector, just push.
 pushToHistory(location);
         else
             // we already navigated. add item at current location, and clear
 // rest of history. (Same as browser behavior.)
 trimHistory(location);
     }


     private boolean isSameLocation(Object location) {
         HistoryObject currentLocation = getCurrentLocation();
         if (location instanceof String && currentLocation.isURL())
             return currentLocation.getUrl().equals(location);

         if (location instanceof AbstractIntroPage
                 && currentLocation.isIntroPage()) {

             AbstractIntroPage locationPage = (AbstractIntroPage) location;
             // be carefull here with calling getPage on historyOvject.
 if (!currentLocation.getPageId().equals(locationPage.getId()))
                 return false;

             // both pages have same ids, they are either both regular pages or
 // both are Iframe pages. check if they have the same IFrame urls
 if (currentLocation.isIFramePage() && locationPage.isIFramePage())
                 return currentLocation.getIFrameUrl().equals(
                     locationPage.getIFrameURL());

             // both pages are not IFrame pages, and they have same id.
 return true;
         }

         return false;
     }




     private void pushToHistory(Object location) {
         history.add(new HistoryObject(location));
         // point the nav location to the end of the vector.
 navigationLocation = getHistoryEndPosition();
     }
     
      public void removeLastHistory() {
         history.remove(getHistoryEndPosition());
         // point the nav location to the end of the vector.
 navigationLocation = getHistoryEndPosition();
     }

     private void trimHistory(Object location) {
         List newHistory = history.subList(0, navigationLocation + 1);
         history = new Vector (newHistory);
         history.add(new HistoryObject(location));
         // point the nav location to the end of the vector.
 navigationLocation = getHistoryEndPosition();
     }

     /**
      * Return the position of the last element in the navigation history. If
      * vector is empty, return 0.
      *
      * @param vector
      * @return
      */
     private int getHistoryEndPosition() {
         if (history.isEmpty())
             return 0;
         return history.size() - 1;
     }

     public void navigateHistoryBackward() {
         if (badNavigationLocation(navigationLocation - 1))
             // do nothing. We are at the begining.
 return;
         --navigationLocation;
     }

     /**
      * Navigate forward in the history.
      *
      * @return
      */
     public void navigateHistoryForward() {
         if (badNavigationLocation(navigationLocation + 1))
             // do nothing. We are at the begining.
 return;
         ++navigationLocation;
     }


     private boolean badNavigationLocation(int navigationLocation) {
         if (navigationLocation < 0 || navigationLocation >= history.size())
             // bad nav location.
 return true;
         return false;
     }


     /**
      * Returns true if the current location in the navigation history represents
      * a URL. False if the location is an Intro Page id.
      *
      * @return Returns the locationIsURL.
      */
     private HistoryObject getCurrentLocation() {
         return (HistoryObject) history.elementAt(navigationLocation);
     }

     public boolean canNavigateForward() {
         return navigationLocation != getHistoryEndPosition() ? true : false;
     }

     public boolean canNavigateBackward() {
         return navigationLocation == 0 ? false : true;
     }

     public boolean currentLocationIsUrl() {
         return getCurrentLocation().isURL();
     }

     public String getCurrentLocationAsUrl() {
         return getCurrentLocation().getUrl();
     }

     public AbstractIntroPage getCurrentLocationAsPage() {
         return getCurrentLocation().getPage();
     }

     public static boolean isURL(String aString) {
         IntroURLParser parser = new IntroURLParser(aString);
         if (parser.hasProtocol())
             return true;
         return false;
     }


     public void clear() {
         history.clear();
         navigationLocation = 0;
     }




 }

